﻿using SimpleTerminal.Library;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
using System.Windows.Forms;
using Win32;

namespace SimpleTerminal.Forms
{
    public class NiceForm : Form
    {
        protected Shadow shadow;
        User32.TagRECT borderThickness;
        private bool isDesignMode;

        protected bool CompositionEnabled()
        {
            int compositionEnabled = 0;
            bool success = User32.DwmIsCompositionEnabled(ref compositionEnabled) == 0x0;
            return compositionEnabled != 0 && success;
        }
        private readonly System.Timers.Timer showShaowTimer = new System.Timers.Timer();
        public NiceForm()
        {
            isDesignMode = IsDesignMode();
            showShaowTimer.Interval = 300;
            showShaowTimer.Enabled = true;
            showShaowTimer.Elapsed += new ElapsedEventHandler(ShowShaowTimerHandler);
            showShaowTimer.AutoReset = false;
        }
        private void ShowShaowTimerHandler(object sender, ElapsedEventArgs e)
        {
            Invoke((EventHandler)delegate
            {
                if (shadow != null)
                {
                    shadow.Visible = true;
                }
            });
        }

        private void ShowShadow()
        {
            showShaowTimer.Start();
        }
        private void HideShadow()
        {
            if (shadow.Visible)
            {
                showShaowTimer.Stop();
                shadow.Visible = false;
            }
        }

#if !HIDE
        private bool createParamsHack;
        protected override CreateParams CreateParams
        {
            get
            {

                var cp = base.CreateParams;
                if (!isDesignMode)
                {
                    cp.Style |= User32.WS_CLIPCHILDREN;
                    if (createParamsHack)
                    {
                        cp.Style &= ~(User32.WS_BORDER | User32.WS_CAPTION | User32.WS_DLGFRAME | User32.WS_THICKFRAME);
                    }
                    else
                    {
                        cp.Style |= (User32.WS_BORDER | User32.WS_CAPTION | User32.WS_DLGFRAME | User32.WS_THICKFRAME | User32.WS_MINIMIZEBOX | User32.WS_MAXIMIZEBOX);
                    }
                }
                //           //if (!_mAeroEnabled)


                return cp;
                // }
                //return base.CreateParams;
            }
        }
#endif



        protected override void OnShown(EventArgs e)
        {
            base.OnShown(e);
            if (shadow != null)
            {
                shadow.UpdateLocation();
            }
        }

        protected override void OnVisibleChanged(EventArgs e)
        {
            base.OnVisibleChanged(e);
            if (shadow != null)
            {
                shadow.Visible = Visible;
            }
        }
        public static bool IsDesignMode()
        {
            bool returnFlag = false;

#if DEBUG
            if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)
            {
                returnFlag = true;
            }
            else if (Process.GetCurrentProcess().ProcessName == "devenv")
            {
                returnFlag = true;
            }
#endif

            return returnFlag;
        }
        protected override void SetClientSizeCore(int x, int y)
        {
            createParamsHack = true;
            base.SetClientSizeCore(x, y);
            createParamsHack = false;
        }

        public new FormWindowState WindowState
        {
            get { return base.WindowState; }
            set
            {
                if (shadow != null)
                {
                    /*if (value == FormWindowState.Normal)
                    {
                        ShowShadow();
                    }
                    else */
                    if (value == FormWindowState.Maximized)
                    {
                        HideShadow();
                    }
                    else if (value == FormWindowState.Minimized)
                    {
                        HideShadow();
                    }
                }
                base.WindowState = value;
            }
        }

        /// <summary>
        /// 在最大化的时候会出现尺寸错误，因此设置padding来弥补
        /// 同时此函数还负责适当的时机显示和隐藏阴影
        /// </summary>
        /// <param name="e"></param>
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);

            if (shadow != null)
            {
                if (WindowState == FormWindowState.Normal)
                {
                    ShowShadow();
                }
                else if (WindowState == FormWindowState.Maximized)
                {
                    HideShadow();
                }
                else if (WindowState == FormWindowState.Minimized)
                {
                    HideShadow();
                }
            }

        }
        protected override void WndProc(ref Message m)
        {
            //Log.Debug("MainForm", m.ToString());
            // if (User32.DwmDefWindowProc(Handle, m.Msg, m.WParam, m.LParam, IntPtr.Zero))
            //     return;
            switch (m.Msg)
            {
                /*
                case 0x00AE:
                case 0x00AF:
                case User32.WM_NCACTIVATE:
                case User32.WM_NCPAINT:
                    GraphicsPath graphicsPath = new GraphicsPath();
                    graphicsPath.StartFigure();
                    graphicsPath.AddLine(8,8,Width - 8,8);
                    graphicsPath.AddLine(Width - 8, 8, Width - 8, Height - 8);
                    graphicsPath.AddLine(Width - 8, Height - 8, 8, Height - 8);
                    graphicsPath.AddLine(8, Height - 8, 8,8);
                    graphicsPath.CloseFigure();
                    this.Region = new Region(graphicsPath);
                    //   base.WndProc(ref m);
                    IntPtr wDc = User32.GetWindowDC(Handle);
                    Graphics graphics = Graphics.FromHdc(wDc);
                    LinearGradientBrush linearGradientBrush = new LinearGradientBrush(
                        new Point(0,0), 
                        new Point(6, 6),
                        Color.Transparent,
                        Color.Black
                        );
                    graphics.FillRectangle(new SolidBrush(Color.Black), 0,0,Width,6);
                    graphics.Dispose();
                    User32.ReleaseDC(Handle,wDc);
                    return;*/

                case User32.WM_WINDOWPOSCHANGED:

                    createParamsHack = true;
                    base.WndProc(ref m);
                    createParamsHack = false;
                    return;
                case User32.WM_CREATE:

#if !HIDE
                    User32.LPRECT lPRECT = new User32.LPRECT();


                    User32.AdjustWindowRectEx(ref borderThickness, (uint)(User32.GetWindowLongW(m.HWnd, -16) & ~User32.WS_CAPTION), false, 0);
                    borderThickness.left *= -1;
                    borderThickness.top *= -1;

                    //Console.WriteLine(borderThickness.left);

                    User32.GetWindowRect(Handle, ref lPRECT);
                    User32.SetWindowPos(Handle,
                                  IntPtr.Zero,
                                  0, 0,
                                  0, 0,
                                  User32.SWP_FRAMECHANGED | User32.SWP_NOSIZE | User32.SWP_NOMOVE);
#endif
#if HIDE
                    if (CompositionEnabled())
                    {
                        //int v1 = 0x01;
                        //User32.DwmSetWindowAttribute(Handle,
                        //     (int)User32.DWMWINDOWATTRIBUTE.DWMWA_ALLOW_NCPAINT, ref v1,4);
                        int v = 2;
                        User32.DwmSetWindowAttribute(Handle,
                            (int)User32.DWMWINDOWATTRIBUTE.DWMWA_NCRENDERING_POLICY, ref v, 4);
                        var margins = new User32.MARGINS
                        {
                            bottomHeight = 0,
                            leftWidth = 0,
                            rightWidth = 0,
                            topHeight = 0
                        };
                        User32.DwmExtendFrameIntoClientArea(Handle, ref margins);
                    }
#endif
                    break;
                case 0x0084:
                    base.WndProc(ref m);
                    Point vPoint = new Point((int)m.LParam & 0xFFFF,
               (int)m.LParam >> 16 & 0xFFFF);
                    vPoint = PointToClient(vPoint);
                    Console.WriteLine(vPoint.ToString());
                    if (vPoint.X <= 8)
                        if (vPoint.Y <= 8)
                            m.Result = (IntPtr)User32.HTTOPLEFT;
                        else if (vPoint.Y >= ClientSize.Height - 8)
                            m.Result = (IntPtr)User32.HTBOTTOMLEFT;
                        else m.Result = (IntPtr)User32.HTLEFT;
                    else if (vPoint.X >= ClientSize.Width - 8)
                        if (vPoint.Y <= 8)
                            m.Result = (IntPtr)User32.HTTOPRIGHT;
                        else if (vPoint.Y >= ClientSize.Height - 8)
                            m.Result = (IntPtr)User32.HTBOTTOMRIGHT;
                        else m.Result = (IntPtr)User32.HTRIGHT;
                    else if (vPoint.Y <= 8)
                        m.Result = (IntPtr)User32.HTTOP;
                    else if (vPoint.Y >= ClientSize.Height - 8)
                        m.Result = (IntPtr)User32.HTBOTTOM;
                    //break;
                    //  Console.WriteLine(m.ToString());
                    return;
                case 0x0201:
                    m.Msg = 0x00A1; //更改消息为非客户区按下鼠标
                    m.LParam = IntPtr.Zero; //默认值
                    m.WParam = new IntPtr(2); //鼠标放在标题栏内
                    break;
#if HIDE
                case User32.WM_NCACTIVATE:

                    if (m.WParam == IntPtr.Zero)
                    {
                        m.Result = (IntPtr)0x01;
                        return;
                    }
                    m.Result = (IntPtr)0x01;
                    return;
                    break;
#endif
#if !HIDE

                case User32.WM_NCCALCSIZE:

                    if (m.WParam != IntPtr.Zero)
                    {
                        if (User32.IsZoomed(Handle))
                        {
                            User32.TagNCCALCSIZE_PARAMS tagNCCALCSIZE_PARAMS =
                                                  (User32.TagNCCALCSIZE_PARAMS)Marshal.PtrToStructure(m.LParam, typeof(User32.TagNCCALCSIZE_PARAMS));

                            tagNCCALCSIZE_PARAMS.rgrc[0].left += 8;
                            tagNCCALCSIZE_PARAMS.rgrc[0].top += 8;
                            tagNCCALCSIZE_PARAMS.rgrc[0].right -= 8;
                            tagNCCALCSIZE_PARAMS.rgrc[0].bottom -= 8;

                            Marshal.StructureToPtr(tagNCCALCSIZE_PARAMS, m.LParam, true);

                        }
                        //m.Result = (IntPtr)(0x20|0x40| 0x100 | 0x200);
                        return;
                    }
                    m.Result = IntPtr.Zero;
                    return;

                //   };


#endif
#if !HIDE
                case User32.WM_ACTIVATE:// BoxShadow.WM_NCPAINT: // box shadow
                    if (CompositionEnabled())
                    {
                        int v = 2;
                        User32.DwmSetWindowAttribute(Handle, 2, ref v, 4);
                        var margins = new User32.MARGINS
                        {
                            bottomHeight = 0,
                            leftWidth = 0,
                            rightWidth = 0,
                            topHeight = 0
                        };
                        User32.DwmExtendFrameIntoClientArea(Handle, ref margins);

                    }
                    break;
#endif
            };
            base.WndProc(ref m);
        }
    }
}
